package com.example.onlinemusic.controller;


import com.example.onlinemusic.model.Music;
import com.example.onlinemusic.model.User;
import com.example.onlinemusic.service.UserService;
import com.example.onlinemusic.tools.Constant;
import com.example.onlinemusic.tools.ResponseBodyMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

@RestController
@RequestMapping("/music")
public class MusicController {

    @Value("${music.local.path}")
    private String Save_path;

    @Autowired
    private UserService userService;

    @RequestMapping("/upload")
    // MultipartFile是Spring框架中处理文件上传的主要类
    public ResponseBodyMessage<Boolean> insertMusic(@RequestParam String singer, @RequestParam("filename") MultipartFile file,
                                                    HttpServletRequest request, HttpServletResponse response) {
        // 没有获取到 Session 不会创建
        HttpSession httpSession = request.getSession(false);
        // 1.验证是否登录，登录成功后才允许上传
        if (httpSession == null || httpSession.getAttribute(Constant.USERINFO_SESSION_KEY) == null) {
            System.out.println("没有登录!");
            return new ResponseBodyMessage<>(-1, "没有登陆，请登录后上传 !", false);
        } else {
            // 获取音乐文件名称及类型 如 xxx.mp3
            String filenameAndType = file.getOriginalFilename();
            System.out.println("filenameAndType--->>>>>>>>>>>>>>>>>" + filenameAndType);

            // 设置文件保存路径 Save_path 采取从配置文件中读取的方式
            String path = Save_path + filenameAndType;

            //2.上传服务器  上传音乐到指定的文件目录
            // 创建文件，该文件路径为 path
            File dest = new File(path);
            if (!dest.exists()) {
                dest.mkdirs();
            }
            try {
                // 将上传的文件保存在 dest 目录下
                file.transferTo(dest);
                //return new ResponseBodyMessage<>(1, "服务器上传音乐成功 !", true);
            } catch (IOException e) {
                e.printStackTrace();
                return new ResponseBodyMessage<>(-1, "服务器上传音乐失败 !", false);
            }

            //3.上传数据库
            //3.1 先准备好歌曲的字段数据
            int LastPointIndex = filenameAndType.lastIndexOf(".");//返回上传文件名称最后一个点的下标
            //数据库当中存储的歌曲名称不包含.mp3. 所以需要进行截取
            String title = filenameAndType.substring(0, LastPointIndex);// substring 截取的是左闭右开区间，我们只需要从0下标到最后一个点的下标

            //SimpleDateFormat来格式化当前的系统时间
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            String time = simpleDateFormat.format(new Date());

            //这里的 url 会被用到播放音乐的模块
            String url = "/music/get?path=" + title;

            User user = (User) httpSession.getAttribute(Constant.USERINFO_SESSION_KEY);
            int userid = user.getId();

            // TODO：这里可以有一步：验证上传的文件在数据库中是否已经存在【判断title 和 singer 是否有和数据库中的数据一致的】
            // 此处遇到的问题：1.端口被进程占用，如何处理！ 先在cmd中查看被那个进程占用，再用命令杀掉该进程
            //              2.mybatis xml文件中，查询语句的返回类型只能是对应的实体，不能是受影响的行数
            Music music = userService.selectinsertMusic(title, singer);

            if (music != null) {
                return new ResponseBodyMessage<>(-1, "该音乐已存在，上传数据库失败!", false);
            } else {
                //3.2 将数据插入数据库
                int ret = userService.insertMusic(title, singer, time, url, userid);

                if (ret == 1) {
                    //Ctrl+alt+T 快速生产 try catch 包裹
                    try {
                        // 当上传数据库成功后，会跳转到音乐列表界面
                        response.sendRedirect("/list.html");
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    return new ResponseBodyMessage<>(1, "数据库上传音乐成功 !", true);
                } else {
                    // 如果上传数据库失败，就会把服务器中的文件删除掉 ！
                    dest.delete();
                    return new ResponseBodyMessage<>(-1, "数据库上传音乐失败,已删除服务器上传的音乐!", false);
                }
            }
        }
    }

    //播放音乐：发送一个请求来获取音乐资源字节文件
    @RequestMapping("/get")
    // ResponseEntity对象是Spring对请求响应的封装。它继承了HttpEntity对象，包含了Http的响应码httpstatus）、响应头（header）、响应体(body)三个部分
    public ResponseEntity<byte[]> getMusic(String path) {
        File file = new File(Save_path + path);// 请求时注意要加上.mp3
        byte[] body = null;
        try {
            // Files.readAllBytes(String path) : 读取文件中的所有字节，读入内存 ，参数path是文件的路径
            body = Files.readAllBytes(file.toPath());
            if (body == null) {
                // 如果 body 此时还为null，说明没有读取到文件，即前端发送了一个错误的请求，没有找到对应的音乐文件
                return ResponseEntity.badRequest().build();// 错误请求，返回 400 状态码
            }
            return ResponseEntity.ok(body);//返回 200 状态码 以及对应的文件字节
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ResponseEntity.badRequest().build();
    }


    //根据单个id 删除单个音乐
    //后期优化：根据id删除可能会出现数据库删除成功，服务器删除成功！但是此时数据库另一个id对应的音乐也是删除的这个音乐(音乐名字相同，歌手不同)，
    //这时该idList在数据库中的音乐就没有删除，但是在服务器上已经删除了该音乐
    @RequestMapping("/delete")
    public ResponseBodyMessage<Boolean> deleteMusicByid(String id) {
        int musicId = Integer.parseInt(id);// PS：如果参数直接是int类型，就会报错，是String类型，将其转换为int 就不会报错 原因不知
        //1.先查询该数据库中该idList是否存在音乐
        Music music = userService.selectMusicById(musicId);
        if (music == null) {
            return new ResponseBodyMessage<>(-1, "数据库中没有你想删除的音乐", false);
        } else {
            //2.删除数据库中的音乐
            int ret = userService.deleteMusicById(musicId);
            if (ret == 1) {
                //3.数据库中删除成功，还要删除服务器中的音乐
                String title = music.getTitle();
                File file = new File(Save_path + title + ".mp3");
                System.out.println("此时文件的路径：" + file.getPath());
                Boolean flg = file.delete();
                if (flg) {
                    //数据库和服务器中的音乐数据被删除后，收藏表中对应的音乐也应被删除
                    userService.deleteLoveMusicById(musicId);
                    return new ResponseBodyMessage<>(1, "数据库删除成功且服务器删除成功且删除收藏表对应的音乐 !", true);
                } else {
                    return new ResponseBodyMessage<>(-1, "数据库删除成功但是服务器删除失败 !", false);
                }
            } else {
                return new ResponseBodyMessage<>(-1, "数据库删除失败 !", false);
            }
        }
    }


    //根据id批量删除  与单个删除逻辑一样，只是需要循环遍历集合来一个一个删除
    @RequestMapping("/deletebatch")
    public ResponseBodyMessage<Boolean> deleteBatchMusic(@RequestParam(value = "id[]") List<Integer> idList) {

        int sum = 0;
        for (int i = 0; i < idList.size(); i++) {
            Music music = userService.selectMusicById(idList.get(i));
            if (music == null) {
                return new ResponseBodyMessage<>(-1, "数据库中没有你想删除的音乐", false);
            } else {
                //2.删除数据库中的音乐
                int ret = userService.deleteMusicById(idList.get(i));
                if (ret == 1) {
                    //3.数据库中删除成功，还要删除服务器中的音乐
                    String title = music.getTitle();
                    File file = new File(Save_path + title + ".mp3");
                    System.out.println("此时文件的路径：" + file.getPath());
                    Boolean flg = file.delete();
                    if (flg) {
                        //数据库和服务器中的音乐数据被删除后，收藏表中对应的音乐也应被删除
                        userService.deleteLoveMusicById(idList.get(i));
                        sum += ret;
                        // 注意：下面语句放开注释，整个功能逻辑就会出错 ！！  花了半小时才找出来0.0
                        //return new ResponseBodyMessage<>(1, "数据库删除成功且服务器删除成功 !", true);
                    } else {
                        return new ResponseBodyMessage<>(-1, "数据库删除成功但是服务器删除失败 !", false);
                    }
                } else {
                    return new ResponseBodyMessage<>(-1, "数据库删除失败 !", false);
                }
            }
        }
        if (sum == idList.size()) {
            return new ResponseBodyMessage<>(1, "批量删除音乐成功 !", true);
        } else {
            return new ResponseBodyMessage<>(-1, "批量删除音乐失败 !", false);
        }
    }


    // 查询音乐
    @RequestMapping("/findmusic")
    //(required=false)可以不传入参数，默认为 true，不传入参数就会报错 ！！                    //该参数要和前端参数对应
    public ResponseBodyMessage<List<Music>> findMusic(@RequestParam(required = false) String musicName) {
        List<Music> musicList = null;
        if (musicName != null) {
            //不为空就进行模糊查询
            musicList = userService.findMusicByMusicName(musicName);
        } else {
            //参数为空就查询全部的音乐
            musicList = userService.findMusic();
        }
        return new ResponseBodyMessage<>(1, "查询到了歌曲信息", musicList);
    }
}
